----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    02:17:18 10/01/2009 
-- Design Name: 
-- Module Name:    program_rx - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity program_rx is
    Port ( clk : in STD_LOGIC;
			  reset: in STD_LOGIC;
			  data_out : out  STD_LOGIC_VECTOR (127 downto 0);
           has_data : out  STD_LOGIC;
			  rd_ack: in STD_LOGIC;
           rd_uart : out  STD_LOGIC;
           rx_empty : in  STD_LOGIC;
           r_data : in  STD_LOGIC_VECTOR (7 downto 0));
end program_rx;

architecture Behavioral of program_rx is
	signal checksum : integer range 0 to 128;
	signal packet : STD_LOGIC_VECTOR (175 downto 0);
	type statetype is ( S0, s01, -- shift byte from uart onto packet
							  S1, --S11, S12, S13, s14, --validate packet
							  s2, s21); -- wait for data to be read
	signal state, next_state : statetype := S0;
begin

state <= next_state;
data_out <= packet ( 159 downto 32 );

process (clk, reset) is
begin
	if (reset = '1') then
		packet <= (others=>'0');
-- 	packet structure (for my own benefit)
--		175 downto 168 -> header
--		167 downto 144 -> reserved
--		143 downto 16 -> data
--		15 downto 8 -> checksum
--		7 downto 0 -> footer
		next_state <= S0;
		checksum <= 0;
		has_data <= '0';
		rd_uart <= '0';
	elsif( rising_edge(clk)) then
		case state is
		
		-- Read and shift if there is data available
		-- also pack some checksum stuff into
		-- these cycles
		when S0 =>
			if (rx_empty = '0') then
				rd_uart <= '1';
				next_state <= S01;
				-- subtract the checksum of the byte that is about
				-- to get pushed off the data section
				
				checksum <= checksum - (CONV_INTEGER(packet(143)) +
												CONV_INTEGER(packet(142)) +
												CONV_INTEGER(packet(141)) +
												CONV_INTEGER(packet(140)) +
												CONV_INTEGER(packet(139)) +
												CONV_INTEGER(packet(138)) +
												CONV_INTEGER(packet(137)) +
												CONV_INTEGER(packet(136)));
			else
				next_state <= S0;
			end if;
		
		when S01 =>
			packet <= r_data & packet(175 downto 8);
			checksum <= checksum + (CONV_INTEGER(r_data(7)) +
											CONV_INTEGER(r_data(6)) +
											CONV_INTEGER(r_data(5)) +
											CONV_INTEGER(r_data(4)) +
											CONV_INTEGER(r_data(3)) +
											CONV_INTEGER(r_data(2)) +
											CONV_INTEGER(r_data(1)) +
											CONV_INTEGER(r_data(0)));
			rd_uart <= '0';
			next_state <= S1;
		
		
		---------------------------------
		-- Packet Validation
		when S1 =>
			if ((packet(7 downto 0) = x"00") and
				 (packet(31 downto 8) = x"000000") and
				 (checksum = CONV_INTEGER(packet(167 downto 160))) and
				 (packet(175 downto 168) = x"FF")) then
				next_state <= S2; -- valid
			else
				next_state <= S0;
			end if;
		
		---------------------------------
		-- wait for implementor to take data
		
		when S2 =>
			if (rd_ack = '1') then
				next_state <= S2;
			else
				has_data <= '1';
				next_state <= S21;
			end if;
		
		when S21 =>
			if (rd_ack = '1') then
				has_data <= '0';
				next_state <= S0;
			else
				next_state <= S21;
			end if;
		
		end case;
	end if;
end process;
				

end Behavioral;

